#include "inc_fan.h"

static uint8_t temp = 0;

static uint8_t mode = 0;
static uint8_t gear = 0;

static uint8_t mustShowGear = 0;

static char uart2RxBuffer[1] = {0};

void PrintTemp() {
    static uint32_t tmpTemp = -1;

    if (tmpTemp == temp) return;

    tmpTemp = temp;

    const uint8_t sub[] = {0, 1, 2};

    OLED_ShowChinese(2, 1, sub, 2);
    OLED_ShowNum(2, 5, temp, 2);
    OLED_ShowChinese(2, 7, sub + 2, 1);
}

void PrintMode() {
    static uint8_t tmpMode = -1;

    if (tmpMode == mode) return;

    tmpMode = mode;

    if (mode == 0) {
        const uint8_t sub[] = {3, 4, 5};
        OLED_ShowChinese(1, 1, sub, 3);

        OLED_Clear_Part(1, 7, 16);
        OLED_Clear_Part(3, 1, 16);
        return;
    }

    mustShowGear = 1;

    if (mode == 1) {
        const char sub[] = {8, 9, 10, 11};
        OLED_ShowChinese(1, 1, (const uint8_t *) sub, 4);
    } else {
        const char sub[] = {6, 7, 10, 11};
        OLED_ShowChinese(1, 1, (const uint8_t *) sub, 4);
    }
}

void PrintGear() {
    static int8_t tmpGear = DEFAULT_GEAR;

    if (mustShowGear || tmpGear != gear) {
        const uint8_t sub[] = {14};

        OLED_ShowNum(3, 1, gear, 2);
        OLED_ShowChinese(3, 3, sub, 1);

        tmpGear = gear;
        mustShowGear = 0;
    }
}

void SetMode(const uint8_t newMode) {
    if (mode == newMode) return;

    mode = newMode;

    if (mode == 0) {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
    } else {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
    }
}

void SetGear(int8_t newGear) {
    static uint32_t pwm = 0;

    if (newGear <= 0) {
        newGear = 1;
    } else if (newGear > NUMBER_OF_GEARS) {
        newGear = NUMBER_OF_GEARS;
    }

    if (newGear == gear) return;

    const uint32_t autoReload = __HAL_TIM_GetAutoreload(&htim3);
    const uint32_t gears = autoReload / NUMBER_OF_GEARS;

    pwm = gears * newGear;
    gear = newGear;

    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwm);
}

void AutoSetTemp() {
    static uint32_t tmpAdcTemp = -1;

    if (HAL_GetTick() % 500 != 0) return;

    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 10);
    const uint32_t adcTemp = HAL_ADC_GetValue(&hadc1);

    if (tmpAdcTemp == adcTemp) return;

    tmpAdcTemp = adcTemp;

    temp = D2t(tmpAdcTemp);
}

void AutoSetGear() {
    static uint8_t tmpTemp = -1;
    static uint8_t tmpGear = DEFAULT_GEAR;

    if (mode != 2 || (tmpTemp == temp && tmpGear == gear)) return;

    tmpTemp = temp;
    tmpGear = tmpTemp / 2 - 8;

    SetGear(tmpGear);
}

void PowerSwitch() {
    static uint8_t latestMode = DEFAULT_MODE;

    if (mode == 0) {
        SetMode(latestMode);
    } else {
        latestMode = mode;
        SetMode(0);
    }
}

void ModeSwitch() {
    if (mode == 0) return;

    if (mode == 1) {
        SetMode(2);
    } else {
        SetMode(1);
    }
}

void GearAdd() {
    if (mode != 1) return;

    SetGear(gear + 1);
}

void GearReduce() {
    if (mode != 1) return;

    SetGear(gear - 1);
}

void ReceiveControl() {
    HAL_UART_Receive_IT(&huart2, (uint8_t *) uart2RxBuffer, 1);
}

void FanExecuteControl() {
    switch (uart2RxBuffer[0]) {
        case '0':
            FanButton(GPIO_PIN_9);
            break;
        case '1':
            FanButton(GPIO_PIN_10);
            break;
        case '2':
            FanButton(GPIO_PIN_11);
            break;
        case '3':
            FanButton(GPIO_PIN_12);
            break;
        default:
            break;
    }
}

void FanSetup() {
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
    HAL_ADCEx_Calibration_Start(&hadc1);
    ReceiveControl();
    SetGear(DEFAULT_GEAR);
    OLED_Init();
}

void FanLoop() {
    AutoSetTemp();
    AutoSetGear();
    PrintMode();
    PrintTemp();
    PrintGear();
}

void FanButton(const uint16_t GPIO_Pin) {
    const char *msg;

    switch (GPIO_Pin) {
        case GPIO_PIN_9:
            msg = "Power switch\r\n";
            PowerSwitch();
            break;
        case GPIO_PIN_10:
            msg = "Mode switch\r\n";
            ModeSwitch();
            break;
        case GPIO_PIN_11: {
            msg = "Gear add\r\n";
            GearAdd();
        }
        break;
        case GPIO_PIN_12: {
            msg = "Gear reduce\r\n";
            GearReduce();
        }
        break;
        default:
            msg = "Unknow button\r\n";
            break;
    }

    HAL_UART_Transmit_DMA(&huart1, (const uint8_t *) msg, strlen(msg));
}

void FanUARTRxCpltCallback() {
    FanExecuteControl();
}
